home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 11
/
Mac Magazin and MacEasy Magazine CD - Issue 11.iso
/
Sharewarebibliothek
/
Entwickler
/
WASTE 1.1b1 Distribution
/
WASTE Source
/
WEHighLevelEditing.p
< prev
next >
Wrap
Text File
|
1995-06-01
|
37KB
|
1,450 lines
unit WEHighLevelEditing;
{ WASTE PROJECT: }
{ High-Level Editing Routines }
{ Copyright © 1993-1994 Marco Piovanelli }
{ All Rights Reserved }
interface
uses
WELowLevelEditing;
const
{ action kinds }
weAKNone = 0; { null action }
weAKUnspecified = 1; { action of unspecified nature }
weAKTyping = 2; { some text has been typed in }
weAKCut = 3; { the selection range has been cut }
weAKPaste = 4; { something has been pasted }
weAKClear = 5; { the selection range has been deleted }
weAKDrag = 6; { drag and drop operation }
weAKSetStyle = 7; { some style has been applied to a text range }
{ action flags }
weAFIsRedo = $0001; { action saves edit state prior to a WEUndo call }
weAFDontSaveText = $0002; { don't save text }
weAFDontSaveStyles = $0004; { don't save styles }
weAFDontSaveSoup = $0008; { don't save embedded object information }
type
WEActionKind = Integer;
WEActionFlags = Integer;
{ a WEAction record is used to record a single editing operation on a WE instance, }
{ like typing some text, cutting or pasting. A linked list of WEAction records might }
{ be used to implement multiple undo. }
WEActionHandle = ^WEActionPtr;
WEActionPtr = ^WEAction;
WEAction = record
hOwner: WEHandle; { handle to associated WE instance }
hNext: WEActionHandle; { used to keep a linked list of actions }
hText: Handle; { handle to saved text }
hStyles: Handle; { handle to saved styles }
hSoup: Handle; { handle to saved "soup" }
delRangeStart: LongInt; { start of range to delete }
delRangeLength: LongInt; { length of range to delete }
insRangeLength: LongInt; { length of range to insert }
hiliteStart: LongInt; { start of range to hilite }
hiliteEnd: LongInt; { end of range to hilite }
actionKind: WEActionKind; { identifies event that caused this action to be pushed }
actionFlags: WEActionFlags; { miscellaneous flags }
end; { WEAction }
{ high-level editing functions }
procedure WEKey (key: Char;
modifiers: Integer;
hWE: WEHandle);
function WEInsert (textPtr: Ptr;
textLength: LongInt;
hStyles: StScrpHandle;
hSoup: Handle;
hWE: WEHandle): OSErr;
function WEInsertObject (objectType: OSType;
objectDataHandle: Handle;
objectSize: Point;
hWE: WEHandle): OSErr;
function WEDelete (hWE: WEHandle): OSErr;
function WECut (hWE: WEHandle): OSErr;
function WEPaste (hWE: WEHandle): OSErr;
function WESetStyle (mode: Integer;
var ts: WETextStyle;
hWE: WEHandle): OSErr;
function WEUseStyleScrap (hStyles: StScrpHandle;
hWE: WEHandle): OSErr;
{ high-level Undo functions }
function WEUndo (hWE: WEHandle): OSErr;
procedure WEClearUndo (hWE: WEHandle);
function WEGetUndoInfo (var redoFlag: Boolean;
hWE: WEHandle): WEActionKind;
{ keeping track of changes }
function WEGetModCount (hWE: WEHandle): LongInt;
procedure WEResetModCount (hWE: WEHandle);
{ actions }
function WENewAction (rangeStart, rangeEnd: LongInt;
newTextLength: LongInt;
actionKind: WEActionKind;
actionFlags: WEActionFlags;
hWE: WEHandle;
var hAction: WEActionHandle): OSErr;
procedure WEDisposeAction (hAction: WEActionHandle);
function WEDoAction (hAction: WEActionHandle): OSErr;
{ low-level routines for directly manipulating }
{ the action stack associated with a given WE instance }
function WEGetActionStack (hWE: WEHandle): WEActionHandle;
function WEPushAction (hAction: WEActionHandle): OSErr;
{ miscellaneous }
function WECanPaste (hWE: WEHandle): Boolean;
procedure _WEAdjustUndoRange (moreBytes: LongInt;
hWE: WEHandle);
function WEIsTyping (hWE: WEHandle): Boolean;
implementation
uses
Scrap, WEScraps;
function WEGetActionStack (hWE: WEHandle): WEActionHandle;
begin
WEGetActionStack := WEActionHandle(hWE^^.hActionStack);
end; { WEGetActionStack }
function WEPushAction (hAction: WEActionHandle): OSErr;
var
pWE: WEPtr;
hLast: WEActionHandle;
begin
WEPushAction := noErr;
{ find the last action in the given stack }
hLast := hAction;
while (hLast^^.hNext <> nil) do
hLast := hLast^^.hNext;
{ prepend hAction in front of the action stack }
pWE := hAction^^.hOwner^;
hLast^^.hNext := WEActionHandle(pWE^.hActionStack);
pWE^.hActionStack := Handle(hAction);
end; { WEPushAction }
function WENewAction (rangeStart, rangeEnd: LongInt;
newTextLength: LongInt;
actionKind: WEActionKind;
actionFlags: WEActionFlags;
hWE: WEHandle;
var hAction: WEActionHandle): OSErr;
label
0, 1;
var
pAction: WEActionPtr;
err: OSErr;
begin
{ allocate a new action record }
err := _WEAllocate(SizeOf(WEAction), kAllocClear, hAction);
if (err <> noErr) then
goto 1;
{ lock it down }
HLock(Handle(hAction));
pAction := hAction^;
{ fill in the fields }
pAction^.hOwner := hWE;
pAction^.delRangeStart := rangeStart;
pAction^.delRangeLength := newTextLength;
pAction^.insRangeLength := rangeEnd - rangeStart;
pAction^.actionKind := actionKind;
pAction^.actionFlags := actionFlags;
{ remember selection range }
WEGetSelection(pAction^.hiliteStart, pAction^.hiliteEnd, hWE);
{ allocate a handle to hold the text to be saved, unless otherwise specified }
if (BAND(actionFlags, weAFDontSaveText) = 0) then
begin
err := _WEAllocate(0, kAllocTemp, pAction^.hText);
if (err <> noErr) then
goto 1;
end;
{ allocate a handle to hold the styles to be saved, unless otherwise specified }
if (BAND(actionFlags, weAFDontSaveStyles) = 0) then
begin
err := _WEAllocate(0, kAllocTemp, pAction^.hStyles);
if (err <> noErr) then
goto 1;
end;
{ allocate a handle to hold the "soup" to be saved, unless otherwise specified }
if (BAND(actionFlags, weAFDontSaveSoup) = 0) then
begin
err := _WEAllocate(0, kAllocTemp, pAction^.hSoup);
if (err <> noErr) then
goto 1;
end;
{ make a copy of text range }
err := WECopyRange(rangeStart, rangeEnd, pAction^.hText, pAction^.hStyles, pAction^.hSoup, hWE);
if (err <> noErr) then
goto 1;
{ unlock action record }
HUnlock(Handle(hAction));
{ skip clean-up section }
goto 0;
1:
{ clean up }
_WEForgetHandle(pAction^.hText);
_WEForgetHandle(pAction^.hStyles);
_WEForgetHandle(pAction^.hSoup);
_WEForgetHandle(hAction);
0:
{ return result code }
WENewAction := err;
end; { WENewAction }
procedure WEDisposeAction (hAction: WEActionHandle);
var
pAction: WEActionPtr;
hNext: WEActionHandle;
begin
while (hAction <> nil) do
begin
{ lock the action record }
HLock(Handle(hAction));
pAction := hAction^;
hNext := pAction^.hNext;
{ throw away text, styles and soup }
_WEForgetHandle(pAction^.hText);
_WEForgetHandle(pAction^.hStyles);
_WEForgetHandle(pAction^.hSoup);
{ throw away the action record itself }
DisposeHandle(Handle(hAction));
{ repeat the same sequence with all linked actions }
hAction := hNext;
end; { while }
end; { WEDisposeAction }
procedure WEForgetAction (var hAction: WEActionHandle);
var
theAction: WEActionHandle;
begin
theAction := hAction;
if (theAction <> nil) then
begin
hAction := nil;
WEDisposeAction(theAction);
end;
end; { WEForgetAction }
function WEDoAction (hAction: WEActionHandle): OSErr;
label
1;
var
hRedoAction: WEActionHandle;
pAction: WEActionPtr;
hWE: WEHandle;
pWE: WEPtr;
offset, delOffset, insOffset: LongInt;
redrawStart, redrawEnd: LongInt;
saveActionLock, saveWELock, saveTextLock: Boolean;
err: OSErr;
begin
{ sanity check: make sure hAction isn't NIL }
if (hAction = nil) then
begin
WEDoAction := nilHandleErr;
Exit(WEDoAction);
end;
{ get handle to associated WE instance }
hWE := hAction^^.hOwner;
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ return an error code if this instance is read-only }
err := weReadOnlyErr;
if (BTST(pWE^.flags, weFReadOnly)) then
goto 1;
{ stop any ongoing inline input session }
WEStopInlineSession(hWE);
{ hide selection highlighting and the caret }
_WEHiliteRange(pWE^.selStart, pWE^.selEnd, hWE);
if BTST(pWE^.flags, weFCaretVisible) then
_WEBlinkCaret(hWE);
redrawStart := maxLongInt;
redrawEnd := 0;
repeat
{ lock the action record }
saveActionLock := _WESetHandleLock(hAction, true);
pAction := hAction^;
offset := pAction^.delRangeStart;
delOffset := offset + pAction^.delRangeLength;
insOffset := offset + pAction^.insRangeLength;
{ if undo support is enabled, save the range to be affected by this action }
if (BTST(pWE^.flags, weFUndoSupport)) then
if (WENewAction(offset, delOffset, pAction^.insRangeLength, pAction^.actionKind, BXOR(pAction^.actionFlags, weAFIsRedo), hWE, hRedoAction) = noErr) then
if (WEPushAction(hRedoAction) <> noErr) then
;
if (pAction^.hText <> nil) then
begin
{ delete the range to replace }
err := _WEDeleteRange(offset, delOffset, hWE);
if (err <> noErr) then
goto 1;
{ insert the saved text }
saveTextLock := _WESetHandleLock(pAction^.hText, true);
err := _WEInsertText(offset, pAction^.hText^, pAction^.insRangeLength, hWE);
if (_WESetHandleLock(pAction^.hText, saveTextLock)) then
;
if (err <> noErr) then
goto 1;
end;
{ apply the saved styles, if any }
if (pAction^.hStyles <> nil) then
begin
err := _WEApplyStyleScrap(offset, insOffset, StScrpHandle(pAction^.hStyles), hWE);
if (err <> noErr) then
goto 1;
end;
{ the same goes for the soup }
if (pAction^.hSoup <> nil) then
begin
err := _WEApplySoup(offset, pAction^.hSoup, hWE);
if (err <> noErr) then
goto 1;
end;
{ adjust redraw range }
if (offset < redrawStart) then
redrawStart := offset;
if (insOffset > redrawEnd) then
redrawEnd := insOffset;
{ unlock action record }
if (_WESetHandleLock(hAction, saveActionLock)) then
;
{ go to next action }
hAction := hAction^^.hNext;
until (hAction = nil);
{ restore the original selection range }
pWE^.selStart := pAction^.hiliteStart;
pWE^.selEnd := pAction^.hiliteEnd;
{ redraw the text }
err := _WERedraw(redrawStart, redrawEnd, hWE);
if (err <> noErr) then
goto 1;
{ clear result code }
err := noErr;
1:
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
{ return result code }
WEDoAction := err;
end; { WEDoAction }
function WEUndo (hWE: WEHandle): OSErr;
var
pWE: WEPtr;
hAction: WEActionHandle;
saveWELock: Boolean;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ "detach" the action stack from the WE instance }
hAction := WEActionHandle(pWE^.hActionStack);
pWE^.hActionStack := nil;
if (hAction <> nil) then
begin
{ undoing a change _decrements_ the modification count; }
{ redoing the change increments it again }
if (BAND(hAction^^.actionFlags, weAFIsRedo) <> 0) then
pWE^.modCount := pWE^.modCount + 1
else
pWE^.modCount := pWE^.modCount - 1;
{ perform the action... }
WEUndo := WEDoAction(hAction);
{ ...and throw it away }
WEDisposeAction(hAction);
end
else
{ return an error code if the undo buffer is empty }
WEUndo := weCantUndoErr;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEUndo }
procedure WEClearUndo (hWE: WEHandle);
begin
{ dispose of the action chain associated with the given WE instance }
WEForgetAction(WEActionHandle(hWE^^.hActionStack));
end; { WEClearUndo }
function WEGetUndoInfo (var redoFlag: Boolean;
hWE: WEHandle): WEActionKind;
begin
WEGetUndoInfo := weAKNone; { assume no actions have been saved }
redoFlag := false;
if (hWE^^.hActionStack <> nil) then
with WEActionHandle(hWE^^.hActionStack)^^ do
begin
WEGetUndoInfo := actionKind;
redoFlag := (BAND(actionFlags, weAFIsRedo) <> 0);
end;
end; { WEGetUndoInfo }
function WEGetModCount (hWE: WEHandle): LongInt;
begin
WEGetModCount := hWE^^.modCount;
end; { WEGetModCount }
procedure WEResetModCount (hWE: WEHandle);
begin
hWE^^.modCount := 0;
WEClearUndo(hWE);
end; { WEResetModCount }
procedure _WEAdjustUndoRange (moreBytes: LongInt;
hWE: WEHandle);
var
hAction: WEActionHandle;
begin
hAction := WEActionHandle(hWE^^.hActionStack);
if (hAction <> nil) then
with hAction^^ do
delRangeLength := delRangeLength + moreBytes;
end; { _WEAdjustUndoRange }
function _WETypeChar (theByte: SignedByte;
hWE: WEHandle): OSErr;
label
0, 1;
var
pWE: WEPtr;
db: DoubleByte;
offset, endOffset, charLength: LongInt;
err: OSErr;
begin
pWE := hWE^; { the WE record must be already locked }
charLength := 1; { assume 1-byte character by default }
db.firstByte := theByte;
offset := pWE^.selStart;
{ delete current selection, if any }
err := _WEDeleteRange(offset, pWE^.selEnd, hWE);
if (err <> noErr) then
goto 1;
pWE^.selEnd := offset; { needed in case we take a premature exit }
{ make sure the font script is synchronized with the keyboard script }
_WESynchNullStyle(hWE);
if BTST(pWE^.flags, weFDoubleByte) then
begin
{ special processing for double-byte characters }
if (pWE^.firstByte <> 0) then
begin
{ if this byte is the second half of a double-byte character, }
{ insert the two bytes at the same time (flush the double-byte cache) }
db.firstByte := pWE^.firstByte;
db.secondByte := theByte;
charLength := 2;
pWE^.firstByte := 0;
end
else
{ if theByte is the first half of a double-byte character, just cache it and exit }
if (CallWECharByteProc(@theByte, 0, FontToScript(pWE^.nullStyle.runStyle.tsFont), hWE, pWE^.charByteHook) = smFirstByte) then
begin
pWE^.firstByte := theByte;
goto 0;
end;
end; { if double-byte script installed }
{ insert the new character into the text }
err := _WEInsertText(offset, @db, charLength, hWE);
if (err <> noErr) then
goto 1;
{ adjust undo buffer for the new character }
_WEAdjustUndoRange(charLength, hWE);
{ invalid the null style }
BCLR(pWE^.flags, weFUseNullStyle);
{ move the insertion point after the new character }
endOffset := offset + charLength;
pWE^.selStart := endOffset;
pWE^.selEnd := endOffset;
{ redraw the text }
err := _WERedraw(offset, endOffset, hWE);
if (err <> noErr) then
goto 1;
0:
{ clear result code }
err := noErr;
1:
{ return result code }
_WETypeChar := err;
end; { _WETypeChar }
function _WEBackspace (hWE: WEHandle): OSErr;
{ this routine is called by WEKey to handle the backspace key }
{ the WE record is guaranteed to be already locked }
label
0, 1;
var
pWE: WEPtr;
pAction: WEActionPtr;
rangeStart, rangeEnd, charLength: LongInt;
pChars: WECharsPtr;
runInfo: WERunInfo;
saveActionLock: Boolean;
err: OSErr;
begin
pWE := hWE^;
{ calculate the text range to delete }
{ if the selection is non-empty, delete that }
rangeStart := pWE^.selStart;
rangeEnd := pWE^.selEnd;
if (rangeStart = rangeEnd) then
begin
{ otherwise the selection is an insertion point }
{ do nothing if insertion point is at the beginning of the text }
if (rangeStart = 0) then
goto 0;
{ determine the byte-type of the character preceding the insertion point }
if (WECharByte(rangeStart - 1, hWE) = smSingleByte) then
charLength := 1
else
charLength := 2;
rangeStart := rangeStart - charLength;
if (pWE^.hActionStack <> nil) then
begin
{ UNDO SUPPORT FOR BACKSPACES }
{ lock the action record }
saveActionLock := _WESetHandleLock(pWE^.hActionStack, true);
pAction := WEActionHandle(pWE^.hActionStack)^;
{ backspaces over the newly entered text aren't a problem }
if (pAction^.delRangeLength > 0) then
pAction^.delRangeLength := pAction^.delRangeLength - charLength
else
begin
{ the hard part comes when backspacing past the new text because }
{ the user is about to delete a character not included in the block we saved }
{ lengthen our saved text handle }
SetHandleSize(pAction^.hText, pAction^.insRangeLength + charLength);
err := MemError;
if (err <> noErr) then
goto 1;
{ move old contents forward }
pChars := WECharsHandle(pAction^.hText)^;
BlockMoveData(@pChars^[0], @pChars^[charLength], pAction^.insRangeLength);
{ prepend the character to be deleted to the beginning of our saved text handle }
pChars^[0] := WEGetChar(rangeStart, hWE);
if (charLength = 2) then
pChars^[1] := WEGetChar(rangeStart + 1, hWE);
{ adjust internal counters }
pAction^.insRangeLength := pAction^.insRangeLength + charLength;
pAction^.delRangeStart := pAction^.delRangeStart - charLength;
{ get style run info associated with the about-to-be-deleted character }
WEGetRunInfo(rangeStart, runInfo, hWE);
{ prepend a new style element to our style scrap, if necessary }
err := _WEPrependStyle(pAction^.hStyles, runInfo, charLength);
if (err <> noErr) then
goto 1;
{ do the same with our object "soup" }
err := _WEPrependObject(pAction^.hSoup, runInfo, charLength);
if (err <> noErr) then
goto 1;
end; { if deleting old text }
{ unlock the action record }
if (_WESetHandleLock(pWE^.hActionStack, saveActionLock)) then
;
end; { if undo support is enabled }
end; { if selection is empty }
err := _WEDeleteRange(rangeStart, rangeEnd, hWE);
if (err <> noErr) then
goto 1;
{ keep track of current selection range }
pWE^.selStart := rangeStart;
pWE^.selEnd := rangeStart;
{ redraw the text }
err := _WERedraw(rangeStart, rangeStart, hWE);
if (err <> noErr) then
goto 1;
0:
{ clear result code }
err := noErr;
1:
{ return result code }
_WEBackspace := err;
end; { _WEBackspace }
function _WEForwardDelete (hWE: WEHandle): OSErr;
{ this routine is called by WEKey to handle the forward delete key }
{ the WE record is guaranteed to be already locked }
label
0, 1;
var
pWE: WEPtr;
pAction: WEActionPtr;
rangeStart, rangeEnd, charLength: LongInt;
runInfo: WERunInfo;
db: DoubleByte;
saveActionLock: Boolean;
err: OSErr;
begin
pWE := hWE^;
{ calculate the text range to delete }
{ if the selection is non-empty, delete that }
rangeStart := pWE^.selStart;
rangeEnd := pWE^.selEnd;
if (rangeStart = rangeEnd) then
begin
{ otherwise the selection is an insertion point }
{ do nothing if insertion point is at the end of the text }
if (rangeStart = pWE^.textLength) then
goto 0;
{ determine the byte-type of the character following the insertion point }
if (WECharByte(rangeStart, hWE) = smSingleByte) then
charLength := 1
else
charLength := 2;
rangeEnd := rangeStart + charLength;
if (pWE^.hActionStack <> nil) then
begin
{ UNDO SUPPORT FOR FORWARD DELETE }
{ lock the action record }
saveActionLock := _WESetHandleLock(pWE^.hActionStack, true);
pAction := WEActionHandle(pWE^.hActionStack)^;
{ make a copy of the character about to be deleted }
db.firstByte := SignedByte(WEGetChar(rangeStart, hWE));
if (charLength = 2) then
db.secondByte := SignedByte(WEGetChar(rangeStart + 1, hWE));
{ append it to the end of our saved text handle }
err := PtrAndHand(@db, pAction^.hText, charLength);
if (err <> noErr) then
goto 1;
{ get style run info associated with the about-to-be-deleted character }
WEGetRunInfo(rangeStart, runInfo, hWE);
{ append a new style element to our style scrap, if necessary }
err := _WEAppendStyle(pAction^.hStyles, runInfo, pAction^.insRangeLength);
if (err <> noErr) then
goto 1;
{ do the same with our object soup }
err := _WEAppendObject(pAction^.hSoup, runInfo, pAction^.insRangeLength);
if (err <> noErr) then
goto 1;
{ adjust internal counters }
pAction^.insRangeLength := pAction^.insRangeLength + charLength;
{ unlock the action record }
if (_WESetHandleLock(pWE^.hActionStack, saveActionLock)) then
;
end; { if undo support is enabled }
end; { if selection is empty }
err := _WEDeleteRange(rangeStart, rangeEnd, hWE);
if (err <> noErr) then
goto 1;
{ keep track of current selection range }
pWE^.selStart := rangeStart;
pWE^.selEnd := rangeStart;
{ redraw the text }
err := _WERedraw(rangeStart, rangeStart, hWE);
if (err <> noErr) then
goto 1;
0:
{ clear result code }
err := noErr;
1:
{ return result code }
_WEForwardDelete := err;
end; { _WEForwardDelete }
function WEIsTyping (hWE: WEHandle): Boolean;
var
pWE: WEPtr;
begin
{ return TRUE if we're tracking a typing sequence in the specified WE instance }
WEIsTyping := false; { assume we aren't }
pWE := hWE^; { the WE record must already be locked }
{ there must be an undo buffer }
if (pWE^.hActionStack = nil) then
Exit(WEIsTyping);
with WEActionHandle(pWE^.hActionStack)^^ do
begin
{ the action kind must be "typing" and the redo flag must be clear }
if (actionKind <> weAKTyping) then
Exit(WEIsTyping);
if (BAND(actionFlags, weAFIsRedo) <> 0) then
Exit(WEIsTyping);
{ finally, the selection range mustn't have moved since the last WEKey }
if ((pWE^.selStart = pWE^.selEnd) and (pWE^.selStart = delRangeStart + delRangeLength)) then
WEIsTyping := true;
end; { with }
end; { WEIsTyping }
procedure WEKey (key: Char;
modifiers: Integer;
hWE: WEHandle);
var
pWE: WEPtr;
hAction: WEActionHandle;
saveWELock: Boolean;
err: OSErr;
begin
err := noErr;
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ hide the caret if it's showing }
if BTST(pWE^.flags, weFCaretVisible) then
_WEBlinkCaret(hWE);
{ hide the cursor (it will show again as soon as it's moved) }
ObscureCursor;
{ dispatch on key class (arrow keys, printable characters, backspace) }
if ((ORD(key) >= kArrowLeft) and (ORD(key) <= kArrowDown)) then
_WEDoArrowKey(ORD(key), modifiers, hWE)
else
{ non-arrow keys modify the text, so make sure editing is allowed }
if (not BTST(pWE^.flags, weFReadOnly)) then
begin
{ are we tracking a typing sequence? }
if (WEIsTyping(hWE) = false) then
begin
{ nope; so start a new one }
{ increment modification count }
pWE^.modCount := pWE^.modCount + 1;
{ if undo support is enabled, create a new action to keep track of the typing }
if (BTST(pWE^.flags, weFUndoSupport)) then
begin
WEClearUndo(hWE);
if (WENewAction(pWE^.selStart, pWE^.selEnd, 0, weAKTyping, 0, hWE, hAction) = noErr) then
if (WEPushAction(hAction) <> noErr) then
;
end;
end; { if WEIsTyping }
if (ORD(key) = kBackspace) then
err := _WEBackspace(hWE)
else if (ORD(key) = kForwardDelete) then
err := _WEForwardDelete(hWE)
else
err := _WETypeChar(ORD(key), hWE);
end; { if not read-only }
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
(*WEKey := err;*)
end; { WEKey }
function WEInsert (textPtr: Ptr;
textLength: LongInt;
hStyles: StScrpHandle;
hSoup: Handle;
hWE: WEHandle): OSErr;
label
1;
var
pWE: WEPtr;
offset, endOffset: LongInt;
hAction: WEActionHandle;
intPasteAction: Integer;
saveWELock: Boolean;
space: SignedByte;
err: OSErr;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
offset := pWE^.selStart;
{ return an error code if this instance is read-only }
err := weReadOnlyErr;
if (BTST(pWE^.flags, weFReadOnly)) then
goto 1;
{ stop any ongoing inline input session }
WEStopInlineSession(hWE);
{ increment modification count }
pWE^.modCount := pWE^.modCount + 1;
{ if undo support is enabled, save current selection range }
if (BTST(pWE^.flags, weFUndoSupport)) then
begin
WEClearUndo(hWE);
if (WENewAction(offset, pWE^.selEnd, textLength, weAKUnspecified, 0, hWE, hAction) = noErr) then
if (WEPushAction(hAction) <> noErr) then
;
end;
{ delete current selection }
err := _WEDeleteRange(offset, pWE^.selEnd, hWE);
if (err <> noErr) then
goto 1;
{ insert the new text at the insertion point }
err := _WEInsertText(offset, textPtr, textLength, hWE);
if (err <> noErr) then
goto 1;
endOffset := offset + textLength;
if (hStyles <> nil) then
begin
{ if a style scrap was supplied, apply it to the newly inserted text }
err := _WEApplyStyleScrap(offset, endOffset, hStyles, hWE);
if (err <> noErr) then
goto 1;
end;
if (hSoup <> nil) then
begin
{ if an object soup was supplied, apply it to the newly inserted text }
err := _WEApplySoup(offset, hSoup, hWE);
if (err <> noErr) then
goto 1;
end;
{ determine whether an extra space should be added before or after the inserted text }
intPasteAction := _WEIntelligentPaste(offset, endOffset, hWE);
{ add the extra space, if necessary }
if (intPasteAction <> weDontAddSpaces) then
begin
space := kSpace;
if (intPasteAction = weAddSpaceOnLeftSide) then
err := _WEInsertText(offset, @space, 1, hWE)
else
err := _WEInsertText(endOffset, @space, 1, hWE);
if (err <> noErr) then
goto 1;
endOffset := endOffset + 1;
{ adjust undo buffer (if any) for the extra space }
_WEAdjustUndoRange(1, hWE);
end;
{ invalid the null style }
BCLR(pWE^.flags, weFUseNullStyle);
{ move the insertion point at the end of the inserted text }
pWE^.selStart := endOffset;
pWE^.selEnd := endOffset;
{ redraw the text }
err := _WERedraw(offset, endOffset, hWE);
if (err <> noErr) then
goto 1;
{ clear result code }
err := noErr;
1:
{ return result code }
WEInsert := err;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEInsert }
function WEInsertObject (objectType: OSType;
objectDataHandle: Handle;
objectSize: Point;
hWE: WEHandle): OSErr;
label
1;
var
pWE: WEPtr;
hAction: WEActionHandle;
offset, endOffset: LongInt;
ts: WETextStyle;
marker: SignedByte;
saveWELock: Boolean;
err: OSErr;
begin
_WEBlockClr(@ts, SizeOf(ts));
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
offset := pWE^.selStart;
{ return an error code if this instance is read-only }
err := weReadOnlyErr;
if (BTST(pWE^.flags, weFReadOnly)) then
goto 1;
{ stop any ongoing inline input session }
WEStopInlineSession(hWE);
{ call the 'new' handler to initialize private object storage (if any) }
{ and to calculate the default size for this object }
err := _WENewObject(objectType, objectDataHandle, hWE, WEObjectDescHandle(ts.tsObject));
if (err <> noErr) then
goto 1;
{ use the specified object size, unless it is (0, 0), in which case keep the default size }
if (LongInt(objectSize) <> 0) then
WEObjectDescHandle(ts.tsObject)^^.objectSize := objectSize;
{ increment modification count }
pWE^.modCount := pWE^.modCount + 1;
{ if undo support is enabled, save current selection range }
if (BTST(pWE^.flags, weFUndoSupport)) then
begin
WEClearUndo(hWE);
if (WENewAction(offset, pWE^.selEnd, 1, weAKUnspecified, 0, hWE, hAction) = noErr) then
if (WEPushAction(hAction) <> noErr) then
;
end;
{ delete current selection }
err := _WEDeleteRange(offset, pWE^.selEnd, hWE);
if (err <> noErr) then
goto 1;
{ insert a kObjectMarker character at the insertion point }
marker := kObjectMarker;
err := _WEInsertText(offset, @marker, 1, hWE);
if (err <> noErr) then
goto 1;
{ move the insertion point after the inserted text }
endOffset := offset + 1;
pWE^.selStart := endOffset;
pWE^.selEnd := endOffset;
{ record a reference to the object descriptor in the style table }
err := _WESetStyleRange(offset, endOffset, weDoObject, ts, hWE);
ts.tsObject := kNullObject;
if (err <> noErr) then
goto 1;
{ invalid the null style }
BCLR(pWE^.flags, weFUseNullStyle);
{ redraw the text }
err := _WERedraw(offset, endOffset, hWE);
if (err <> noErr) then
goto 1;
{ clear result code }
err := noErr;
1:
{ return result code }
WEInsertObject := err;
{ clean up }
_WEForgetHandle(ts.tsObject);
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEInsertObject }
function WEDelete (hWE: WEHandle): OSErr;
label
1;
var
pWE: WEPtr;
hAction: WEActionHandle;
rangeStart, rangeEnd: LongInt;
saveWELock: Boolean;
err: OSErr;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ return an error code if this instance is read-only }
err := weReadOnlyErr;
if (BTST(pWE^.flags, weFReadOnly)) then
goto 1;
{ stop any ongoing inline input session }
WEStopInlineSession(hWE);
{ get current selection range }
rangeStart := pWE^.selStart;
rangeEnd := pWE^.selEnd;
{ do nothing if the selection range is empty }
if (rangeStart < rangeEnd) then
begin
{ increment modification count }
pWE^.modCount := pWE^.modCount + 1;
{ range extension for intelligent cut-and-paste }
_WEIntelligentCut(rangeStart, rangeEnd, hWE);
{ if undo support is enabled, save the range to be deleted }
if (BTST(pWE^.flags, weFUndoSupport)) then
begin
WEClearUndo(hWE);
if (WENewAction(rangeStart, rangeEnd, 0, weAKClear, 0, hWE, hAction) = noErr) then
if (WEPushAction(hAction) <> noErr) then
;
end;
{ delete the selection range }
err := _WEDeleteRange(rangeStart, rangeEnd, hWE);
if (err <> noErr) then
goto 1;
{ reset the selection range }
pWE^.selStart := rangeStart;
pWE^.selEnd := rangeStart;
{ redraw the text }
err := _WERedraw(rangeStart, rangeStart, hWE);
if (err <> noErr) then
goto 1;
end; { if non-empty selection }
{ clear result code }
err := noErr;
1:
{ return result code }
WEDelete := err;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEDelete }
function WECut (hWE: WEHandle): OSErr;
label
1;
var
err: OSErr;
begin
{ first copy... }
err := WECopy(hWE);
if (err <> noErr) then
goto 1;
{ ...then delete }
err := WEDelete(hWE);
if (err <> noErr) then
goto 1;
{ change the action kind of the most recent action, if any }
if (hWE^^.hActionStack <> nil) then
WEActionHandle(hWE^^.hActionStack)^^.actionKind := weAKCut;
{ clear result code }
err := noErr;
1:
{ return result code }
WECut := err;
end; { WECut }
function WECanPaste (hWE: WEHandle): Boolean;
var
scrapOffset: LongInt;
objectType: OSType;
index: Integer;
begin
WECanPaste := false; { assume failure }
if (not BTST(hWE^^.flags, weFReadOnly)) then
begin
{ return TRUE if the desk scrap contains a text flavor }
if (GetScrap(nil, kTypeText, scrapOffset) > 0) then
begin
WECanPaste := true;
Exit(WECanPaste);
end;
{ see if the desk scrap contains a flavor matching one of the registered object types }
index := 0;
while (_WEGetIndObjectType(index, objectType, hWE) = noErr) do
begin
if (GetScrap(nil, objectType, scrapOffset) > 0) then
begin
WECanPaste := true;
Exit(WECanPaste);
end;
index := index + 1;
end; { while }
end; { if not read-only }
end; { WECanPaste }
function WEPaste (hWE: WEHandle): OSErr;
label
1;
var
hItem: Handle;
hStyles: Handle;
hSoup: Handle;
selStart: LongInt;
scrapOffset: LongInt;
objectType: OSType;
index: Integer;
err: OSErr;
begin
hItem := nil;
hStyles := nil;
hSoup := nil;
selStart := hWE^^.selStart;
{ allocate a handle to hold a scrap item }
err := _WEAllocate(0, kAllocTemp, hItem);
if (err <> noErr) then
goto 1;
{ look for a text flavor }
if (GetScrap(hItem, kTypeText, scrapOffset) <= 0) then
begin
{ no text: look for a flavor matching one of the registered object types }
index := 0;
while (_WEGetIndObjectType(index, objectType, hWE) = noErr) do
begin
if (GetScrap(hItem, objectType, scrapOffset) > 0) then
begin
{ found a registered type: create a new object out of the tagged data }
err := WEInsertObject(objectType, hItem, Point(0), hWE);
{ if successful, set hItem to NIL so clean-up section won't kill the object data }
if (err = noErr) then
hItem := nil;
goto 1;
end;
{ try with next flavor }
index := index + 1;
end; { while }
{ nothing pasteable: return an error code }
err := noTypeErr;
goto 1;
end;
{ allocate a handle to hold the style scrap, if any }
err := _WEAllocate(0, kAllocTemp, hStyles);
if (err <> noErr) then
goto 1;
{ look for a 'styl' item accompanying the text }
if (GetScrap(hStyles, kTypeStyles, scrapOffset) <= 0) then
{ forget the handle if nothing was found or an error occurred }
_WEForgetHandle(hStyles);
{ allocate a handle to hold the soup, if any }
err := _WEAllocate(0, kAllocTemp, hSoup);
if (err <> noErr) then
goto 1;
{ look for a 'SOUP' item accompanying the text }
if (GetScrap(hSoup, kTypeSoup, scrapOffset) <= 0) then
{ forget the handle if nothing was found or an error occurred }
_WEForgetHandle(hSoup);
{ lock down the text }
HLock(hItem);
{ insert the text }
err := WEInsert(hItem^, GetHandleSize(hItem), StScrpHandle(hStyles), hSoup, hWE);
1:
{ if successful, change the action kind of the most recent action, if any }
if (err = noErr) then
if (hWE^^.hActionStack <> nil) then
WEActionHandle(hWE^^.hActionStack)^^.actionKind := weAKPaste;
{ clean up }
_WEForgetHandle(hItem);
_WEForgetHandle(hStyles);
_WEForgetHandle(hSoup);
{ return result code }
WEPaste := err;
end; { WEPaste }
function WESetStyle (mode: Integer;
var ts: WETextStyle;
hWE: WEHandle): OSErr;
label
1;
var
pWE: WEPtr;
hAction: WEActionHandle;
fontScript: ScriptCode;
saveWELock: Boolean;
err: OSErr;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ return an error code if this instance is read-only }
err := weReadOnlyErr;
if (BTST(pWE^.flags, weFReadOnly)) then
goto 1;
{ stop any ongoing inline input session }
WEStopInlineSession(hWE);
if (pWE^.selStart = pWE^.selEnd) then
begin
{ NULL SELECTION }
{ first make sure the nullStyle field contains valid information }
_WESynchNullStyle(hWE);
{ apply style changes to the nullStyle record }
_WECopyStyle(ts, pWE^.nullStyle.runStyle, pWE^.nullStyle.runStyle.tsFace, mode);
{ if the font was altered, synchronize the keyboard script }
if BTST(pWE^.flags, weFNonRoman) then
if BTST(mode, kModeFont) then
begin
fontScript := FontToScript(pWE^.nullStyle.runStyle.tsFont);
if (fontScript <> GetScriptManagerVariable(smKeyScript)) then
KeyScript(fontScript);
end;
end
else
begin
{ NON-EMPTY SELECTION }
{ increment modification count }
pWE^.modCount := pWE^.modCount + 1;
{ if undo support is enabled, save the styles of the text range to be affected }
if (BTST(pWE^.flags, weFUndoSupport)) then
begin
WEClearUndo(hWE);
if (WENewAction(pWE^.selStart, pWE^.selEnd, pWE^.selEnd - pWE^.selStart, weAKSetStyle, weAFDontSaveText + weAFDontSaveSoup, hWE, hAction) = noErr) then
if (WEPushAction(hAction) <> noErr) then
;
end;
{ set the style of the selection range }
err := _WESetStyleRange(pWE^.selStart, pWE^.selEnd, mode, ts, hWE);
if (err <> noErr) then
goto 1;
{ and redraw the text }
err := _WERedraw(pWE^.selStart, pWE^.selEnd, hWE);
if (err <> noErr) then
goto 1;
end;
{ clear the result code }
err := noErr;
1:
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
{ return result code }
WESetStyle := err;
end; { WESetStyle }
function WEUseStyleScrap (hStyles: StScrpHandle;
hWE: WEHandle): OSErr;
label
1;
var
pWE: WEPtr;
saveWELock: Boolean;
err: OSErr;
begin
{ lock the WE record }
saveWELock := _WESetHandleLock(hWE, true);
pWE := hWE^;
{ return an error code if this instance is read-only }
err := weReadOnlyErr;
if (BTST(pWE^.flags, weFReadOnly)) then
goto 1;
{ apply the style scrap to the selection range }
err := _WEApplyStyleScrap(pWE^.selStart, pWE^.selEnd, hStyles, hWE);
if (err <> noErr) then
goto 1;
{ redraw the text }
err := _WERedraw(pWE^.selStart, pWE^.selEnd, hWE);
1:
{ return result code }
WEUseStyleScrap := err;
{ unlock the WE record }
if (_WESetHandleLock(hWE, saveWELock)) then
;
end; { WEUseStyleScrap }
end.